package com.nekonomics
package domain.service

import api.dto.request.AddCartReq
import api.dto.response.{CartItemDto, PageResponseDto}
import persistence.query.{CartItemDetailRepo, SkuDetailRepo, SkuSpecDetailRepo}
import persistence.repository.CartItemRepo
import utils.DoobieUtil.*

import doobie.hikari.HikariTransactor
import zio.*

trait CartService {
  def addItem(userId: Long, req: AddCartReq): DomainIO[Long]

  def cartItems(userId: Long, pageNum: Int, pageSize: Int): DomainIO[PageResponseDto[CartItemDto]]

  def removeItems(userId: Long, skuIds: Set[Long]): DomainIO[Int]

}

object CartService {
  val live: ZLayer[Any, Throwable, CartService] = (config.layers ++ persistence.layers) >>> ZLayer.fromFunction(CartServiceLive.apply)

}

case class CartServiceLive(
  xa: HikariTransactor[Task],
  skuSpecDetailRepo: SkuSpecDetailRepo,
  skuDetailRepo: SkuDetailRepo,
  cartItemRepo: CartItemRepo,
  cartItemDetailRepo: CartItemDetailRepo
)
  extends CartService {

  override def addItem(userId: Long, req: AddCartReq): DomainIO[Long] =
    cartItemRepo.upsert(userId, req.skuId, req.quantity)
      .convertWithXa(xa)


  override def cartItems(userId: Long, pageNum: Int, pageSize: Int): DomainIO[PageResponseDto[CartItemDto]] = {
    val tx = for {
      cartItems <- cartItemDetailRepo.listPageByUserId(userId, pageNum, pageSize)
      total <- cartItemDetailRepo.countByUserId(userId)
    } yield (cartItems, total)

    for {
      (cartItems, total) <- tx.convertWithXa(xa)
      details <- ZIO.foreach(cartItems) { ci =>
        skuSpecDetailRepo.listSpecsBySkuId(ci.skuId).convertWithXa(xa)
          .map(CartItemDto.of(ci,  _))
      }
    } yield PageResponseDto(
      items = details,
      pageNum = pageNum,
      pageSize = pageSize,
      total = total
    )
  }


  override def removeItems(userId: Long, skuIds: Set[Long]): DomainIO[Int] = {
    cartItemRepo.delete(userId, skuIds.toList).convertWithXa(xa)
  }
}
